#ifndef _B5M_OBJECT_MANAGER_H_
#define _B5M_OBJECT_MANAGER_H_

#include "common.h"
#include "B5M_Thread_Mutex.h"
#include "B5m_Guard.h"
#include "B5M_CleanUp.h"

B5M_BEGIN_VERSIONED_NAMESPACE_DECL
/**
 * @class B5M_Object_Manager
*/
class B5M_Object_Manager
{
public:
	enum Object_Manager_State
	{
		OBJ_MAN_UNINITIALIZED = 0,
		OBJ_MAN_INITIALIZING,
		OBJ_MAN_INITIALIZED,
		OBJ_MAN_SHUTTING_DOWN,
		OBJ_MAN_SHUT_DOWN
	};

	enum Preallocated_Object
	{
		B5M_STATIC_OBJECT_LOCK,
		B5M_SINGLETON_RECURSIVE_THREAD_LOCK,
		B5M_PREALLOCATED_OBJECTS  // This enum value must be last!
	};	
  /**
   * Returns 1 before the B5M_Object_Manager has been constructed.
   * This flag can be used to determine if the program is constructing
   * static objects.  If no static object spawns any threads, the
   * program will be single-threaded when this flag returns 1.  (Note
   * that the program still might construct some static objects when
   * this flag returns 0, if ACE_HAS_NONSTATIC_OBJECT_MANAGER is not
   * defined.)
   */
  static int starting_up (void);

  /**
   * Returns 1 after the B5M_Object_Manager has been destroyed.  This
   * flag can be used to determine if the program is in the midst of
   * destroying static objects.  (Note that the program might destroy
   * some static objects before this flag can return 1, if
   * ACE_HAS_NONSTATIC_OBJECT_MANAGER is not defined.)
   */
  static int shutting_down (void);

  /**
   * Accesses a non-recursive B5M_Thread_Mutex to be used for
   * construction of B5M_Singletons.  Returns 0, and the lock in the
   * argument, on success; returns -1 on failure.
   */
  static int get_singleton_lock (B5M_Thread_Mutex *&);

   /**
   * Accessor to singleton instance.  Because static member functions
   * are provided in the interface, this should not be public.  However,
   * it is public so that ACE_Managed_Object<TYPE> can access it.
   */
  static B5M_Object_Manager *instance (void);

  /**
   * Explicitly initialize (construct the singleton instance of) the
   * B5M_Object_Manager.  Returns 0 on success, -1 on failure, and 1
   * if it had already been called.
   */
  virtual int init (void);

  /**
   * Explicitly destroy the singleton instance of the
   * B5M_Object_Manager.  Returns 0 on success, -1 on failure, and 1
   * if it had already been called.
   */
  virtual int fini (void);
   /**
   * Register an ACE_Cleanup object for cleanup at process
   * termination.  The object is deleted via the
   * <ace_cleanup_destroyer>.  If you need more flexiblity, see the
   * @c other at_exit method below.  For OS's that do not have
   * processes, cleanup takes place at the end of <main>.  Returns 0
   * on success.  On failure, returns -1 and sets errno to: EAGAIN if
   * shutting down, ENOMEM if insufficient virtual memory, or EEXIST
   * if the object (or array) had already been registered.
   */
  static int at_exit (B5M_Cleanup *object, void *param = 0, const char* name = 0);

    /**
   * Register an object (or array) for cleanup at process termination.
   * "cleanup_hook" points to a (global, or static member) function
   * that is called for the object or array when it to be destroyed.
   * It may perform any necessary cleanup specific for that object or
   * its class.  "param" is passed as the second parameter to the
   * @a cleanup_hook function; the first parameter is the object (or
   * array) to be destroyed.  @a cleanup_hook, for example, may delete
   * the object (or array).  For OS's that do not have processes, this
   * function is the same as <at_thread_exit>.  Returns 0 on success.
   * On failure, returns -1 and sets errno to: EAGAIN if shutting
   * down, ENOMEM if insufficient virtual memory, or EEXIST if the
   * object (or array) had already been registered.
   */
  static int at_exit (void *object,
                      B5M_CLEANUP_FUNC cleanup_hook,
                      void *param,
                      const char* name = 0);

  /// Remove an object for deletion at program termination.
  /// See description of static version above for return values.
  static int remove_at_exit(void *object);

  /// Table of preallocated objects.
  static void *preallocated_object[B5M_PREALLOCATED_OBJECTS];

protected:
	 /**
   * Returns 1 before B5M_Object_Manager has been constructed.
   * This flag can be used to determine if the program is constructing
   * static objects.  If no static object spawns any threads, the
   * program will be single-threaded when this flag returns 1.  (Note
   * that the program still might construct some static objects when
   * this flag returns 0, if ACE_HAS_NONSTATIC_OBJECT_MANAGER is not
   * defined.)
   */
  int starting_up_i (void);

  /**
   * Returns 1 after B5M_Object_Manager has been destroyed.  This
   * flag can be used to determine if the program is in the midst of
   * destroying static objects.  (Note that the program might destroy
   * some static objects before this flag can return 1, if
   * B%M_HAS_NONSTATIC_OBJECT_MANAGER is not defined.)
   */
  int shutting_down_i (void);

  /// State of the Object_Manager;
  Object_Manager_State object_manager_state_;

  /**
   * Flag indicating whether the ACE_Object_Manager was dynamically
   * allocated by ACE. (If is was dynamically allocated by the
   * application, then the application is responsible for destroying
   * it.)
  */
  bool dynamically_allocated_;

public:
	B5M_Object_Manager(void);
	~B5M_Object_Manager(void);
private:
	/// Register an object or array for deletion at program termination.
	/// See description of static version above for return values.
	int at_exit_i (void *object, B5M_CLEANUP_FUNC cleanup_hook, void *param, const char* name);

	/// Remove an object for deletion at program termination.
	/// See description of static version above for return values.
	int remove_at_exit_i (void *object);

	/// For at_exit support.
	B5M_Exit_Info exit_info_;

	/// Lock that is used to guard internal structures.
	B5M_Recursive_Thread_Mutex *internal_lock_;

	/// Singleton pointer.
	static B5M_Object_Manager *instance_;
};

B5M_END_VERSIONED_NAMESPACE_DECL

#endif